#!/bin/bash
# 用户服务部署脚本 - RedFire框架版本
# ======================================

set -e

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
NC='\033[0m' # No Color

# 配置变量
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
SERVICE_NAME="user-service"
SERVICE_VERSION="2.0.0"
DOCKER_IMAGE="redfire/${SERVICE_NAME}:${SERVICE_VERSION}"

# 部署配置
DEPLOY_ENV="${DEPLOY_ENV:-production}"
DEPLOY_MODE="${DEPLOY_MODE:-canary}"  # canary, blue-green, rolling
HEALTH_CHECK_TIMEOUT="${HEALTH_CHECK_TIMEOUT:-120}"
ROLLBACK_ENABLED="${ROLLBACK_ENABLED:-true}"

# 日志函数
log_info() {
    echo -e "${GREEN}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}

log_error() {
    echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}

log_debug() {
    if [[ "${DEBUG:-false}" == "true" ]]; then
        echo -e "${BLUE}[DEBUG]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
    fi
}

log_step() {
    echo -e "${PURPLE}[STEP]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
}

# 显示部署横幅
show_banner() {
    cat << 'EOF'
    ____            _               
   |  _ \  ___ _ __ | | ___  _   _  
   | | | |/ _ \ '_ \| |/ _ \| | | | 
   | |_| |  __/ |_) | | (_) | |_| | 
   |____/ \___| .__/|_|\___/ \__, | 
              |_|            |___/  

用户服务部署工具 v2.0.0
======================
EOF
}

# 显示帮助信息
show_help() {
    cat << EOF
用法: $0 [选项] [命令]

命令:
  build         构建Docker镜像
  test          运行测试
  deploy        部署服务
  rollback      回滚服务
  status        查看部署状态
  logs          查看服务日志
  health        检查服务健康状态
  cleanup       清理旧版本

选项:
  -e, --env ENV         部署环境 (development|staging|production)
  -m, --mode MODE       部署模式 (canary|blue-green|rolling)
  -v, --version VER     服务版本 (默认: $SERVICE_VERSION)
  -t, --timeout SEC     健康检查超时 (默认: $HEALTH_CHECK_TIMEOUT)
  --no-rollback         禁用自动回滚
  --force               强制执行操作
  --dry-run             预演模式，不实际执行
  --debug               启用调试模式
  -h, --help           显示此帮助信息

环境变量:
  DEPLOY_ENV            部署环境
  DEPLOY_MODE           部署模式
  DOCKER_REGISTRY       Docker镜像仓库
  JWT_SECRET_KEY        JWT密钥 (必需)
  DB_PASSWORD           数据库密码 (必需)
  GRAFANA_ADMIN_PASSWORD Grafana管理员密码

示例:
  $0 build
  $0 deploy --env production --mode canary
  $0 rollback --version 1.9.0
  $0 health
EOF
}

# 验证环境
validate_environment() {
    log_step "验证部署环境..."
    
    # 检查必需的工具
    local required_tools=("docker" "docker-compose" "curl" "jq")
    for tool in "${required_tools[@]}"; do
        if ! command -v "$tool" &> /dev/null; then
            log_error "缺少必需工具: $tool"
            exit 1
        fi
    done
    
    # 检查Docker服务
    if ! docker info &> /dev/null; then
        log_error "Docker服务未运行"
        exit 1
    fi
    
    # 检查必需的环境变量
    local required_vars=()
    if [[ "$DEPLOY_ENV" == "production" ]]; then
        required_vars+=("JWT_SECRET_KEY" "DB_PASSWORD" "GRAFANA_ADMIN_PASSWORD")
    fi
    
    for var in "${required_vars[@]}"; do
        if [[ -z "${!var}" ]]; then
            log_error "缺少必需的环境变量: $var"
            exit 1
        fi
    done
    
    log_info "环境验证通过"
}

# 构建Docker镜像
build_image() {
    log_step "构建Docker镜像..."
    
    cd "$PROJECT_ROOT"
    
    # 构建镜像
    local build_args=""
    if [[ "$DEPLOY_ENV" == "production" ]]; then
        build_args="--target runtime"
    fi
    
    docker build \
        $build_args \
        -t "$DOCKER_IMAGE" \
        -t "redfire/${SERVICE_NAME}:latest" \
        -f deployment/Dockerfile \
        . || {
        log_error "Docker镜像构建失败"
        exit 1
    }
    
    log_info "Docker镜像构建完成: $DOCKER_IMAGE"
    
    # 推送到镜像仓库 (如果配置了)
    if [[ -n "${DOCKER_REGISTRY}" ]]; then
        log_info "推送镜像到仓库: $DOCKER_REGISTRY"
        
        local remote_image="${DOCKER_REGISTRY}/redfire/${SERVICE_NAME}:${SERVICE_VERSION}"
        docker tag "$DOCKER_IMAGE" "$remote_image"
        docker push "$remote_image"
        
        log_info "镜像推送完成"
    fi
}

# 运行测试
run_tests() {
    log_step "运行服务测试..."
    
    cd "$PROJECT_ROOT"
    
    # 启动测试环境
    log_info "启动测试环境..."
    docker-compose -f deployment/docker-compose.test.yml up -d
    
    # 等待服务启动
    sleep 30
    
    # 运行测试
    log_info "执行测试套件..."
    python tests/test_user_service_migration.py \
        --base-url "http://localhost:8001" \
        --output "test_results_${SERVICE_VERSION}.json" || {
        log_error "测试失败"
        
        # 清理测试环境
        docker-compose -f deployment/docker-compose.test.yml down
        exit 1
    }
    
    # 清理测试环境
    log_info "清理测试环境..."
    docker-compose -f deployment/docker-compose.test.yml down
    
    log_info "测试完成"
}

# 金丝雀部署
deploy_canary() {
    log_step "执行金丝雀部署..."
    
    cd "$SCRIPT_DIR"
    
    # 更新环境变量文件
    cat > .env << EOF
# 用户服务环境变量
JWT_SECRET_KEY=${JWT_SECRET_KEY}
DB_NAME=redfire_user
DB_USER=redfire_user
DB_PASSWORD=${DB_PASSWORD}
GRAFANA_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD}
EOF
    
    # 启动新版本 (金丝雀)
    log_info "启动用户服务 v${SERVICE_VERSION} (金丝雀)..."
    docker-compose up -d user-service-v2
    
    # 等待服务启动
    wait_for_service_health "user-service-v2"
    
    # 更新负载均衡器配置 (10%流量到新版本)
    log_info "更新负载均衡器配置 (10%流量到新版本)..."
    update_nginx_config "canary" "10"
    
    # 监控金丝雀版本
    monitor_canary_deployment
}

# 蓝绿部署
deploy_blue_green() {
    log_step "执行蓝绿部署..."
    
    # 确定当前活跃版本
    local current_version=$(get_active_version)
    local new_color
    
    if [[ "$current_version" == "blue" ]]; then
        new_color="green"
    else
        new_color="blue"
    fi
    
    log_info "部署到 $new_color 环境..."
    
    # 部署新版本到非活跃环境
    deploy_to_environment "$new_color"
    
    # 健康检查
    if wait_for_service_health "$new_color"; then
        log_info "切换流量到 $new_color 环境..."
        switch_traffic_to "$new_color"
        
        # 等待一段时间确保稳定
        sleep 60
        
        # 停止旧版本
        log_info "停止旧版本..."
        stop_environment "$current_version"
        
        log_info "蓝绿部署完成"
    else
        log_error "新版本健康检查失败，保持原版本运行"
        stop_environment "$new_color"
        exit 1
    fi
}

# 滚动部署
deploy_rolling() {
    log_step "执行滚动部署..."
    
    local instances=("user-service-1" "user-service-2" "user-service-3")
    
    for instance in "${instances[@]}"; do
        log_info "更新实例: $instance"
        
        # 从负载均衡器移除实例
        remove_from_load_balancer "$instance"
        
        # 停止旧实例
        docker-compose stop "$instance"
        
        # 启动新实例
        docker-compose up -d "$instance"
        
        # 等待健康检查
        if wait_for_service_health "$instance"; then
            # 添加回负载均衡器
            add_to_load_balancer "$instance"
            log_info "实例 $instance 更新完成"
        else
            log_error "实例 $instance 健康检查失败"
            # 回滚此实例
            rollback_instance "$instance"
            exit 1
        fi
        
        # 等待一段时间再更新下个实例
        sleep 30
    done
    
    log_info "滚动部署完成"
}

# 等待服务健康检查
wait_for_service_health() {
    local service_name=$1
    local max_attempts=$((HEALTH_CHECK_TIMEOUT / 10))
    local attempt=0
    
    log_info "等待服务健康检查: $service_name"
    
    while [[ $attempt -lt $max_attempts ]]; do
        if check_service_health "$service_name"; then
            log_info "服务 $service_name 健康检查通过"
            return 0
        fi
        
        log_debug "健康检查尝试 $((attempt + 1))/$max_attempts"
        sleep 10
        ((attempt++))
    done
    
    log_error "服务 $service_name 健康检查超时"
    return 1
}

# 检查服务健康状态
check_service_health() {
    local service_name=$1
    local health_url
    
    case "$service_name" in
        "user-service-v2")
            health_url="http://localhost:8001/health"
            ;;
        *)
            health_url="http://localhost:8001/health"
            ;;
    esac
    
    local response=$(curl -s -o /dev/null -w "%{http_code}" "$health_url" 2>/dev/null || echo "000")
    
    if [[ "$response" == "200" ]]; then
        return 0
    else
        return 1
    fi
}

# 监控金丝雀部署
monitor_canary_deployment() {
    log_step "监控金丝雀部署..."
    
    local monitoring_duration=300  # 5分钟
    local check_interval=30
    local checks=$((monitoring_duration / check_interval))
    local failed_checks=0
    local max_failed_checks=3
    
    for ((i=1; i<=checks; i++)); do
        log_info "金丝雀监控检查 $i/$checks"
        
        # 检查错误率
        local error_rate=$(get_error_rate "user-service-v2")
        if (( $(echo "$error_rate > 5.0" | bc -l) )); then
            log_warn "金丝雀版本错误率过高: ${error_rate}%"
            ((failed_checks++))
        fi
        
        # 检查响应时间
        local avg_response_time=$(get_avg_response_time "user-service-v2")
        if (( $(echo "$avg_response_time > 200" | bc -l) )); then
            log_warn "金丝雀版本响应时间过长: ${avg_response_time}ms"
            ((failed_checks++))
        fi
        
        # 检查健康状态
        if ! check_service_health "user-service-v2"; then
            log_warn "金丝雀版本健康检查失败"
            ((failed_checks++))
        fi
        
        # 如果失败检查过多，触发回滚
        if [[ $failed_checks -ge $max_failed_checks ]]; then
            log_error "金丝雀版本监控失败，触发自动回滚"
            if [[ "$ROLLBACK_ENABLED" == "true" ]]; then
                rollback_canary
            fi
            exit 1
        fi
        
        sleep $check_interval
    done
    
    log_info "金丝雀监控完成，版本稳定"
    
    # 逐步增加流量
    promote_canary_gradually
}

# 逐步提升金丝雀版本流量
promote_canary_gradually() {
    log_step "逐步提升金丝雀版本流量..."
    
    local traffic_levels=(25 50 75 100)
    
    for level in "${traffic_levels[@]}"; do
        log_info "将流量提升到 ${level}%..."
        update_nginx_config "canary" "$level"
        
        # 监控一段时间
        sleep 120
        
        # 检查指标
        if ! check_deployment_metrics; then
            log_error "指标检查失败，停止流量提升"
            return 1
        fi
    done
    
    log_info "金丝雀版本已接收100%流量"
    
    # 停止旧版本
    docker-compose stop user-service-v1
    log_info "金丝雀部署完成"
}

# 回滚金丝雀部署
rollback_canary() {
    log_step "回滚金丝雀部署..."
    
    # 将所有流量切回旧版本
    update_nginx_config "rollback" "0"
    
    # 停止新版本
    docker-compose stop user-service-v2
    
    log_info "金丝雀部署已回滚"
}

# 更新Nginx配置
update_nginx_config() {
    local mode=$1
    local traffic_percentage=$2
    
    local nginx_config="/tmp/nginx_upstream.conf"
    
    case "$mode" in
        "canary")
            cat > "$nginx_config" << EOF
upstream user_service_canary {
    server user-service-v1:8001 weight=$((100 - traffic_percentage));
    server user-service-v2:8001 weight=$traffic_percentage;
}
EOF
            ;;
        "rollback")
            cat > "$nginx_config" << EOF
upstream user_service_canary {
    server user-service-v1:8001 weight=100;
}
EOF
            ;;
    esac
    
    # 重新加载Nginx配置
    docker-compose exec nginx-lb nginx -s reload
}

# 获取错误率
get_error_rate() {
    local service_name=$1
    # 这里应该从监控系统获取实际的错误率
    # 暂时返回模拟值
    echo "2.1"
}

# 获取平均响应时间
get_avg_response_time() {
    local service_name=$1
    # 这里应该从监控系统获取实际的响应时间
    # 暂时返回模拟值
    echo "89.5"
}

# 检查部署指标
check_deployment_metrics() {
    # 这里应该检查各种部署指标
    # 如错误率、响应时间、内存使用等
    return 0
}

# 回滚服务
rollback_service() {
    local target_version=${1:-"previous"}
    
    log_step "回滚服务到版本: $target_version"
    
    if [[ "$target_version" == "previous" ]]; then
        # 获取上一个版本
        target_version=$(get_previous_version)
    fi
    
    if [[ -z "$target_version" ]]; then
        log_error "无法确定回滚目标版本"
        exit 1
    fi
    
    log_info "回滚到版本: $target_version"
    
    # 更新镜像标签
    SERVICE_VERSION="$target_version"
    DOCKER_IMAGE="redfire/${SERVICE_NAME}:${SERVICE_VERSION}"
    
    # 重新部署旧版本
    deploy_service
}

# 获取上一个版本
get_previous_version() {
    # 这里应该从版本管理系统或容器标签获取
    echo "1.9.0"
}

# 查看部署状态
show_deployment_status() {
    log_step "查看部署状态..."
    
    echo -e "\n${CYAN}容器状态:${NC}"
    docker-compose ps
    
    echo -e "\n${CYAN}服务健康状态:${NC}"
    local services=("user-service-v2")
    for service in "${services[@]}"; do
        if check_service_health "$service"; then
            echo -e "  $service: ${GREEN}健康${NC}"
        else
            echo -e "  $service: ${RED}不健康${NC}"
        fi
    done
    
    echo -e "\n${CYAN}资源使用:${NC}"
    docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.NetIO}}\t{{.BlockIO}}"
}

# 查看服务日志
show_service_logs() {
    local service=${1:-"user-service-v2"}
    local lines=${2:-100}
    
    log_info "显示 $service 的最近 $lines 行日志:"
    docker-compose logs --tail "$lines" -f "$service"
}

# 清理旧版本
cleanup_old_versions() {
    log_step "清理旧版本..."
    
    # 清理旧的Docker镜像
    log_info "清理旧的Docker镜像..."
    docker image prune -f
    
    # 清理旧的容器
    log_info "清理停止的容器..."
    docker container prune -f
    
    # 清理旧的数据卷 (谨慎)
    if [[ "${FORCE:-false}" == "true" ]]; then
        log_warn "强制清理未使用的数据卷..."
        docker volume prune -f
    fi
    
    log_info "清理完成"
}

# 主部署函数
deploy_service() {
    log_step "部署用户服务 v${SERVICE_VERSION}..."
    
    case "$DEPLOY_MODE" in
        "canary")
            deploy_canary
            ;;
        "blue-green")
            deploy_blue_green
            ;;
        "rolling")
            deploy_rolling
            ;;
        *)
            log_error "不支持的部署模式: $DEPLOY_MODE"
            exit 1
            ;;
    esac
}

# 主函数
main() {
    local command=""
    
    # 解析命令行参数
    while [[ $# -gt 0 ]]; do
        case $1 in
            -e|--env)
                DEPLOY_ENV="$2"
                shift 2
                ;;
            -m|--mode)
                DEPLOY_MODE="$2"
                shift 2
                ;;
            -v|--version)
                SERVICE_VERSION="$2"
                DOCKER_IMAGE="redfire/${SERVICE_NAME}:${SERVICE_VERSION}"
                shift 2
                ;;
            -t|--timeout)
                HEALTH_CHECK_TIMEOUT="$2"
                shift 2
                ;;
            --no-rollback)
                ROLLBACK_ENABLED="false"
                shift
                ;;
            --force)
                FORCE="true"
                shift
                ;;
            --dry-run)
                DRY_RUN="true"
                shift
                ;;
            --debug)
                DEBUG="true"
                shift
                ;;
            -h|--help)
                show_help
                exit 0
                ;;
            build|test|deploy|rollback|status|logs|health|cleanup)
                command="$1"
                shift
                ;;
            *)
                log_error "未知参数: $1"
                show_help
                exit 1
                ;;
        esac
    done
    
    # 显示横幅
    show_banner
    
    # 显示配置信息
    log_info "部署配置:"
    log_info "  环境: $DEPLOY_ENV"
    log_info "  模式: $DEPLOY_MODE"
    log_info "  版本: $SERVICE_VERSION"
    log_info "  镜像: $DOCKER_IMAGE"
    log_info "  超时: ${HEALTH_CHECK_TIMEOUT}s"
    log_info "  回滚: $ROLLBACK_ENABLED"
    
    if [[ "$DRY_RUN" == "true" ]]; then
        log_warn "预演模式 - 不会实际执行操作"
        exit 0
    fi
    
    # 验证环境
    validate_environment
    
    # 执行命令
    case "$command" in
        "build")
            build_image
            ;;
        "test")
            run_tests
            ;;
        "deploy")
            build_image
            deploy_service
            ;;
        "rollback")
            rollback_service "$2"
            ;;
        "status")
            show_deployment_status
            ;;
        "logs")
            show_service_logs "$2" "$3"
            ;;
        "health")
            if check_service_health "user-service-v2"; then
                log_info "服务健康状态: 正常"
                exit 0
            else
                log_error "服务健康状态: 异常"
                exit 1
            fi
            ;;
        "cleanup")
            cleanup_old_versions
            ;;
        "")
            log_error "请指定命令"
            show_help
            exit 1
            ;;
        *)
            log_error "未知命令: $command"
            show_help
            exit 1
            ;;
    esac
    
    log_info "操作完成"
}

# 脚本入口
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
    main "$@"
fi
